iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
自我挑戰組

Hello SQL 初次見面你好系列 第 14

Day 14 什麼是 SQL 觸發器 (Triggers)

  • 分享至 

  • xImage
  •  

觸發器(Triggers) 是資料庫的回呼函式(CallBack),當我們在對資料表進行特定類型的修改操作時(如 INSERT、UPDATE 或 DELETE)時自動執行。觸發器可以用於檢查或修改數據,維護資料表之間的引用完整性,記錄變更等

觸發器(Triggers)的類型:

  1. BEFORE Triggers: 在相關操作執行前執行
  2. AFTER Triggers: 在相關操作執行後執行
  3. INSTEAD OF Triggers: 替代原來的操作執行 (常用在檢視表(VIEW))

一樣我們使用實際案例來帶入觸發器(Triggers) 該如何使用

假設我們有一個 `orders` table,
每當新的訂單被加入時,我們希望自動在 `order_logs` table 中寫入一條記錄

1. 首先我們先做好 orders & order_logs table

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    amount NUMERIC,
    create_at TIMESTAMPTZ
)
CREATE TABLE order_logs (
    id SERIAL PRIMARY KEY,
    order_id INT,
    action CHARACTER VARYING
);

2. 再來我們就要用到我們昨天提到的 UDFs(自訂函數),並提供給 Trigger 使用

-- 自訂函數 UDF

CREATE OR REPLACE FUNCTION log_order_insert()
RETURNS TRIGGER AS -- 這邊要 return 的類型為 `TRIGGER`

$$
BEGIN
    INSERT INTO order_logs (order_id, action)
    VALUES (NEW.id, 'INSERT');
    RETURN NEW; -- 必須 return New,這代表正在寫入的那筆資料,因為 transaction 還沒完成
END; 
$$ LANGUAGE plpgsql;

CREATE FUNCTION
這邊有使用到 `NEW` 這個特殊的變數,是我們在定義 function 給 trigger 時使用到的

- NEW: 對於 INSERT 和 UPDATE 操作,NEW 代表了新插入或更新後的資料的數據
- OLD:對於 UPDATE 和 DELETE 操作,OLD 代表了更新前或刪除前的行的數據

Example: 我們可以使用 New.column_name 去拿到他的值,就像我們上面所使用的 `NEW.id`

3. 建立觸發器 (TRIGGER)

-- Create TRIGGER (觸發器)

CREATE TRIGGER tr_log_order_insert
AFTER INSERT ON orders -- 觸發時機:當 Insert into orders 資料表之後觸發
FOR EACH ROW -- Insert to 的每一行都會執行這個觸發器
EXECUTE PROCEDURE log_order_insert(); -- 執行我們剛剛建立的 `log_order_insert()` 函數

CREATE TRIGGER

驗證一下使否有成功執行

INSERT INTO orders (amount) VALUES (999), (1000) RETURNING *;
 id | amount | create_at
----+--------+-----------
  1 |    999 |
  2 |   1000 |
(2 rows)

INSERT 0 2

-----------------

SELECT * FROM order_logs;

 id | order_id | action
----+----------+--------
  1 |        1 | INSERT
  2 |        2 | INSERT
(2 rows)

如何刪除 trigger

DROP TRIGGER tr_log_order_insert ON orders; -- 後面要記得加上 `ON table_name`

DROP TRIGGER

CREATE Trigger 語法

剛剛我們使用一個 order 的例子來帶入如何使用 Trigger
現在我們來說明一下 Trigger 的語法

CREATE TRIGGER your_trigger_name

{ BEFORE || AFTER || INSTEAD OF } event

ON table_name

FOR EACH { ROW || STATEMENT }

WHEN (condition)

EXECUTE PROCEDURE example_function();

{ BEFORE || AFTER || INSTEAD OF }

  • BEFORE:觸發器會在相關事件發生之前執行
  • AFTER:觸發器會在相關事件發生之後執行
  • INSTEAD OF:通常用於視圖,使觸發器在相應的事件發生時替代原始的插入、更新或刪除操作

event

  • event: 可以是 INSERT、UPDATE、DELETE 或 TRUNCATE
  • 或是若是有多種事件都會觸發的話可以這樣寫 INSERT OR UPDATE OR ...

{ ROW || STATEMENT }

  • FOR EACH ROW:對於涉及表中每一行的事件,觸發器都會執行
  • FOR EACH STATEMENT:對於影響表的每個 SQL 語句,觸發器都會執行
-- 假如是 FOR EACH ROW 的設定的話
INSERT TO orders VALUES (123), (456), (789);
-- 這樣 trigger 會觸發 3 次


-- 假如是 FOR EACH STATEMENT 的設定的話
INSERT TO orders VALUES (123), (456), (789);
-- 這樣 trigger 只會觸發 1 次

WHEN (condition)

  • 當滿足此條件時,觸發器才會執行
  • 舉例 WHEN (New.name is NOT NULL)
  • 表示當先寫入的資料 name 欄位不為空的時候會觸發 trigger

Trigger 的注意事項:

  1. 性能考慮: 過多或過於複雜的觸發器可能會對性能產生影響,特別是在高負載的系統中
  2. 調整困難: 觸發器的錯誤可能會比較難以追蹤和調整,因為它們是在後台運行的
  3. 複雜性: 過度依賴觸發器可能會導致系統變得過於複雜和難以管理

雖然觸發器是一個強大的工具,能夠幫助我們自動執行一些操作和維護數據完整性,
但我們也需要謹慎使用,以避免不必要的複雜性和性能問題


上一篇
Day 13: SQL 函數 & 預存程序 (Stored Procedure)
下一篇
Day 15 SQL 檢視表(VIEW)
系列文
Hello SQL 初次見面你好30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言